package com.bridgeintelligent.tag.bulkload.service.core;

import com.bridgeintelligent.tag.bulkload.api.*;
import com.bridgeintelligent.tag.bulkload.api.fileload.FileLoadModel;
import com.bridgeintelligent.tag.bulkload.api.fileload.FileLoadResult;
import com.bridgeintelligent.tag.bulkload.api.fileload.FilterGroup;
import com.bridgeintelligent.tag.bulkload.service.core.cache.CacheConfig;
import com.bridgeintelligent.tag.bulkload.service.core.cache.CacheUtils;
import com.bridgeintelligent.tag.bulkload.service.es.ESUtils;
import com.bridgeintelligent.tag.bulkload.service.es.query.EsQueryBuilder;
import com.bridgeintelligent.tag.bulkload.service.time.IEsDateService;
import com.bridgeintelligent.tag.mapper.DimDataMapper;
import com.bridgeintelligent.tag.remotefile.RemoteFileHandler;
import com.bridgeintelligent.tag.utils.DateHelper;
import com.bridgeintelligent.tag.utils.FieldHandler;
import com.wayneleo.quickstart.framework.ExceptionCode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.Strings;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author JackCheung
 * @date 2020/5/7 1:45 PM.
 * description:
 */
@Slf4j
@AllArgsConstructor
@Service
public class FileLoadHandler {

    private static final String ALL_EXPORT_SIGN = "0";
    private static final String SPLIT_SIGN = ",";
    private static final String DIVIDE_SIGN = "|";
    private RemoteFileHandler remoteFileHandler;
    private static final String LOCAL_FILE_FORMAT = "/tmp/%s.txt";
    private static final String DIM_FORMAT = "%s_%s";
    private static final String SUB_SIGN = "_";

    private static final String SHOW_VALUE_AND_ORIGINAL_NAME = "标签值中文名+标签值";
    private static final String SHOW_VALUE_AND_ORIGINAL_VALUE = "05";

    private static final String LAST_CLOSING_DATE = "last_closing_date";

    private DimDataMapper dimDataMapper;

    private IEsDateService dateService;

    public FileLoadResult handler(FileExportDto fileExportDto, FilterGroup filterGroup) {

        FileLoadModel fileLoadModel = createFileLoad(fileExportDto, filterGroup);
        File file = new File(String.format(LOCAL_FILE_FORMAT, fileExportDto.getId()));
        if (!file.exists()) {
            file.getParentFile()
                .mkdir();
        }
        try (FileOutputStream fos = new FileOutputStream(file); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(fos))) {
            StringBuilder stringBuilder = new StringBuilder();
            Map<String, String> realKeymap = new LinkedHashMap<>(fileLoadModel.getIncludes().length);
            String lastClose = "";
            for (String s : fileLoadModel.getIncludes()) {
                if (s.startsWith(LAST_CLOSING_DATE)){
                    lastClose = s;
                }else{
                    realKeymap.put(s, FieldHandler.reduceSuffixField(s,fileExportDto.getDataDate()));
                }
            }
            for (String s : fileLoadModel.getIncludes()) {
                if (!s.startsWith(LAST_CLOSING_DATE)){
                    String dimName = Optional.ofNullable((DimInfo) CacheUtils.getCacheInfo(CacheConfig.DIM_INFO, realKeymap.get(s)))
                            .map(DimInfo::getDimName)
                            .orElse(realKeymap.get(s));
                    stringBuilder.append(dimName)
                            .append(DIVIDE_SIGN);
                }
            }
            bufferedWriter.write(stringBuilder.toString());
            bufferedWriter.newLine();
            //IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, indexId);
            //因为多索引改造，索引可能变化频繁，这里不再从缓存里读取信息，直接通过索引ID查询索引信息
            IndexNameInfo indexNameInfo = dimDataMapper.findIndexInfoById(fileExportDto.getIndexId());
            AtomicInteger num = new AtomicInteger();
            writeHandler(indexNameInfo, fileLoadModel, num, realKeymap, bufferedWriter,lastClose);
            bufferedWriter.close();
            return new FileLoadResult(num.get(), remoteFileHandler.uploadWhiteList(file.getAbsolutePath(), fileExportDto.getId()));
        } catch (IOException e) {
            e.printStackTrace();
            log.error("写入本地文件出现异常", e);
            throw new BulkLoadException(new ExceptionCode(999, "写入本地文件出现异常"));
        }
    }

    private void writeHandler(IndexNameInfo indexNameInfo, FileLoadModel fileLoadModel, AtomicInteger num, Map<String, String> realKeymap, BufferedWriter bufferedWriter,String lastClose) {
        ESUtils.scrollSearch(indexNameInfo.getDataDate(), fileLoadModel, hits -> {
            for (SearchHit hit : hits) {
                StringBuilder tmp = new StringBuilder();
                num.getAndIncrement();

                //特殊处理逻辑
                Object checkClose =  hit.getSourceAsMap().get(lastClose);
                if (checkClose != null && Integer.parseInt(checkClose.toString().substring(0,4)) <= Integer.parseInt(DateHelper.currentDateTime(DateHelper.PATTERN_DATE_6))){
                    realKeymap.forEach((k,v) ->{
                        Object source = hit.getSourceAsMap().get(k);
                        if (k.equals(BulkLoadConfig.CUST_NO) || k.equals(BulkLoadConfig.ECIF_ID)){
                            String queryResult = source == null ? SUB_SIGN : source.toString();
                            tmp.append(queryResult).append(DIVIDE_SIGN);
                        }else{
                            tmp.append(SUB_SIGN).append(DIVIDE_SIGN);
                        }
                    });
                }else{
                    realKeymap.forEach((k, v) -> {
                        Object source = hit.getSourceAsMap()
                                .get(k);
                        DimInfo dimInfo = CacheUtils.getCacheInfo(CacheConfig.DIM_INFO, realKeymap.get(k));
                        String showType = Optional.ofNullable(dimInfo)
                                .map(DimInfo::getDimeShowType)
                                .orElse("03");//如果为空则showType为03
                        if(source instanceof List){
                            List<Object> values = (List<Object>) source;
                            String result = values.stream().map(value->{
                                String itemName =
                                        Optional.ofNullable((DimItemInfo) CacheUtils.getCacheInfo(CacheConfig.DIM_ITEM_INFO, String.format(DIM_FORMAT, realKeymap.get(k), value)))
                                                .map(DimItemInfo::getDimItemName)
                                                .orElse(value.toString());
                                if (SHOW_VALUE_AND_ORIGINAL_VALUE.equalsIgnoreCase(showType)||SHOW_VALUE_AND_ORIGINAL_NAME.equalsIgnoreCase(showType)) {
                                    return String.format(DIM_FORMAT,itemName,value);
                                } else {
                                    return StringUtils.isEmpty(itemName) ? value.toString() : itemName;
                                }
                            }).collect(Collectors.joining(","));
                            tmp.append(result)
                                    .append(DIVIDE_SIGN);
                        } else {
                            String queryResult = source == null ? SUB_SIGN : source.toString();
                            String result=Optional.ofNullable((DimItemInfo) CacheUtils.getCacheInfo(CacheConfig.DIM_ITEM_INFO, String.format(DIM_FORMAT, realKeymap.get(k), queryResult)))
                                    .map(DimItemInfo::getDimItemName)
                                    .orElse(queryResult);
                            if (SHOW_VALUE_AND_ORIGINAL_VALUE.equalsIgnoreCase(showType) || SHOW_VALUE_AND_ORIGINAL_NAME.equalsIgnoreCase(showType)) {
                                result =String.format(DIM_FORMAT,result,queryResult);
                            }
                            tmp.append(result)
                                    .append(DIVIDE_SIGN);
                        }
                    });
                }
                bufferedWriter.write(tmp.toString());
                bufferedWriter.newLine();
            }
        });
    }

    private FileLoadModel createFileLoad(FileExportDto fileExportDto, FilterGroup filterGroup) {
        FileLoadModel fileLoadModel = new FileLoadModel();
        if (FieldHandler.FALSE.equals(fileExportDto.getTimeType())){
            fileLoadModel.setQueryBuilder(EsQueryBuilder.buildFilter(filterGroup));
        }else{
            fileLoadModel.setQueryBuilder(QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,fileExportDto.getCustomerId()));
        }
        fileLoadModel.setExcludes(Strings.EMPTY_ARRAY);
        fileLoadModel.setIncludes(choseIncludes(fileExportDto));
        return fileLoadModel;
    }

    private String[] choseIncludes(FileExportDto fileExportDto) {
        if (ALL_EXPORT_SIGN.equals(fileExportDto.getExportField())) {
            return CacheUtils.getCacheMap(CacheConfig.DIM_INFO)
                             .entrySet()
                             .stream()
                             .map(Map.Entry::getKey)
                             .toArray(String[]::new);
        } else {
            Map<String, String> relation = dateService.symbolRelation(fileExportDto.getIndexId());
            return Arrays.stream(fileExportDto.getFieldValue().split(SPLIT_SIGN))
                         .filter(StringUtils::isNotEmpty)
                         .map(s -> {
                             return FieldHandler.addSuffixField(s,fileExportDto.getDataDate(),relation);
                         })
                         .toArray(String[]::new);
        }
    }



}
